<template>
  <component
    ref="formRef"
    :is="is ? 'a-form' : 'div'"
    :model="formParam"
    v-bind="formConfig"
  >
    <!-- 表单/搜索 -->
    <Form
      v-if="form"
      v-bind="props"
      @query="query"
      @reset="reset"
      @changeValue="(data) => emit('changeValue', data)"
    >
      <!-- 导出插槽 -->
      <template v-for="(value, name) in $slots" #[name]="slotData">
        <slot v-bind="slotData || {}" :name="name" />
      </template>
    </Form>
    <!-- 中间层：信息/按钮等 -->
    <div :class="toolConfig ? 'operate' : ''">
      <slot v-bind="{ loading }" name="info" />
      <!-- 列设置：不可丢title里面，除非去除全选列展示 -->
      <a-space v-if="toolConfig">
        <a-popover
          trigger="click"
          placement="topLeft"
          overlayClassName="table-column-settings"
          arrow-point-at-center
        >
          <a-tooltip
            v-if="toolConfig?.setting"
            title="列设置"
            class="tool-item"
          >
            <setting-outlined />
          </a-tooltip>
          <template #content>
            <Setting :columns="columns" @ColumnChange="onColumnChange" />
          </template>
        </a-popover>
      </a-space>
    </div>
    <!-- 列表 -->
    <a-form-item v-if="columns" :label="label">
      <a-table
        ref="tableRef"
        size="small"
        :rowKey="(rowKey) => rowKey.id"
        :dataSource="keys ? formParam[keys] : tableData"
        :columns="toolConfig ? columnsSetting : columns"
        :pagination="paginationConfig"
        :loading="loading"
        v-bind="$attrs"
      >
        <!-- 需要被a-form包裹效验才可生效 -->
        <template
          v-if="columnsSetting.length"
          #bodyCell="{ column, record, index }"
        >
          <!-- 可以不要这个，index切换分页就重置了 -->
          <template v-if="column.dataIndex === 'index' && !column.type">
            {{ index + 1 }}
          </template>
          <template v-else-if="column.type">
            <a-form-item
              :name="keys ? [keys, index, column.dataIndex] : null"
              :rules="
                column.rules
                  ? findConfig(column.rules, formConfig)
                  : {
                      required:
                        typeof column.required === 'function'
                          ? column.required({ record })
                          : findConfig(column.required, formConfig),
                      message:
                        column.m ||
                        column.message ||
                        `${rulesMessage[column.type]}${column.title}`,
                    }
              "
              :labelCol="{ span: 24 }"
              :wrapperCol="{ span: 24 }"
            >
              <!-- a-form-item标签包裹：默认插槽 -->
              <slot v-bind="{ column, record, index }">
                <template v-if="column.dataIndex === 'index'">
                  {{ index + 1 }}
                </template>
                <!-- 框架 -->
                <Frames
                  v-bind="props"
                  :formParam="record"
                  :data="{ ...column, record, index }"
                  @changeValue="(data) => emit('changeValue', data)"
                />
              </slot>
            </a-form-item>
          </template>
          <!-- 默认插槽 -->
          <slot v-else v-bind="{ column, record, index }" />
        </template>
        <!-- a-table：本身插槽 -->
        <template v-for="(value, name) in $slots" #[name]="slotData">
          <slot v-bind="slotData || {}" :name="name" />
        </template>
      </a-table>
    </a-form-item>
  </component>
</template>

<script setup>
import { ref, reactive, onMounted } from "vue";
import { propsConfig, findConfig, rulesMessage } from "./utils/index";
import Form from "./form.vue";
import Frames from "./utils/index.vue";
import Setting from "./utils/setting.vue";

/** 项目列表添加行/审批居多，可使用此封装组件，分页也可 */
const emit = defineEmits(["changeValue"]);
const props = defineProps({
  /**
   * 是否内嵌 a-form 表单
   * is：true表示内嵌a-form标签
   * is：false则使用需要在最外层父组件使用 a-form标签包裹组件，因为在使用validate()等方法复用性高
   */
  is: { type: Boolean, default: true },
  // 是否内联
  inline: { type: Boolean, default: true },
  // 间隔，查询和重置的col定义
  colSpan: { type: Number },
  // table表格label
  label: { type: String, default: null },
  // form表单是否需要label
  isLabel: { type: Boolean, default: true },
  // 列表字段，用于效验，新增删除
  keys: { type: String, default: null },
  // 表格列的配置
  columns: { type: Array, default: null },
  // 接口
  apiFn: { type: Function, default: null },
  // 在父组件使用xxRef.value.setFn的时候，传递一个函数替换掉getFn方法
  setFn: { type: Function, default: null },
  // 传递默认值，default: () => ({ current: 1, size: 10 }),
  apiParam: { type: Object, default: null },
  // 配置工具栏
  toolConfig: { type: Object, default: null },
  ...propsConfig,
});

// ref
const formRef = ref(null);

// 列设置
const columnsSetting = ref(props.columns);
const onColumnChange = (val) => {
  columnsSetting.value = val.filter(
    (value) => value.checked === undefined || value.checked
  );
};

// 分页配置
const paginationConfig = reactive({
  current: 1,
  pageSize: 10,
  pageSizeOptions: ["10", "20", "50", "100"],
  showSizeChanger: true,
  showTotal: (total) => `共 ${total} 条`,
  onChange: (current, size) => {
    paginationConfig.current = current;
    paginationConfig.pageSize = size;
    updateFormParams({ current, size });
    refresh();
  },
});

/**
 * 修改apiFn父组件传递的接口，并暴露给父组件
 * 防止传递默认参数失效时使用调用setFn函数修改
 */
const setFn = (newFn, params) => getFn(newFn, params);

// 获取接口列表
const loading = ref(false);
const tableData = ref([]);
const getFn = async (newFn, params = {}) => {
  const { keys, apiFn, apiParam, formParam } = props;
  if (!apiFn && !newFn) return;
  const fn = apiFn || newFn;
  console.log(
    { ...formParam, ...apiParam, ...params },
    "列表参数：搜索“getFn”删除打印结果"
  );
  loading.value = true;
  try {
    const { data = [], total = 0 } = await fn({
      ...formParam,
      ...apiParam,
      ...params,
    });
    if (keys) {
      formParam[keys] = data;
      return;
    }
    tableData.value = data;
    paginationConfig.total = total;
    /**
     * 根据自己数据结构调整
    if (keys) {
			formParam.value[keys] = res.records ? res.records : res || []
			return
		}
		tableData.value = res.records ? res.records : res || []
    paginationConfig.total = total;
    */
  } catch (error) {
    console.error("请求失败:", error);
  } finally {
    loading.value = false;
  }
};

// 更新分页
const updatePagination = (data) => Object.assign(paginationConfig, data);
// 更新传递默认值
const updateFormParams = (data) => Object.assign(props.apiParam, data);

// 查询
const query = (callback) => {
  // 返回第一页
  if (props.apiParam) {
    updatePagination({ current: 1 });
    updateFormParams({ current: 1 });
  }
  callback && callback();
  refresh();
};
// 重置
const reset = (callback) => {
  const { formParam } = props;
  for (const key in formParam) {
    formParam[key] = undefined;
  }
  callback && callback();
  // 如果不需要重置返回第一页，可以默认调用refresh方法
  query();
};
// 刷新
const refresh = (callback) => {
  callback && callback();
  (props.setFn && props.setFn()) || getFn();
};

onMounted(() => {
  // 不建议默认refresh，获取其他接口params的时候会导致接口已经调用，参数没获取的情况
  getFn();
});

defineExpose({
  validate: () => formRef.value?.validate(),
  resetFields: () => formRef.value?.resetFields(),
  setFn,
  refresh,
  query,
  reset,
});
</script>

<style lang="scss" scoped>
.operate {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  margin-bottom: 10px;
}
</style>
